/************************************************************************/
/* File: MultiThreadEventManager.h	Author: BG Studio, Justin Lee	    */
/* Description:									                        */
/* Declaration of CMultiThreadEventManager and CMultiThreadEvent.	    */
/* Interfaces of our multi-thread event engine.			                */
/* Tested both on Windows and Linux.                                    */
/************************************************************************/
#ifndef __MULTITHREADEVENTMANAGER_H__
#define __MULTITHREADEVENTMANAGER_H__
#include <stdlib.h>
#include <deque>
#include <vector>
#if defined(WIN32)
#include "pthread.h"
#include "semaphore.h"
#else
#include <pthread.h>
#include <semaphore.h>
#endif

#ifndef PTHREAD_THREADS_MAX
#define PTHREAD_THREADS_MAX 64
#endif

class CMultiThreadEventManager;

/**
 * Realize your event by inheriting this class
 */
class CMultiThreadEvent
{
public:
	CMultiThreadEvent();
	virtual ~CMultiThreadEvent();
	/**
	 * Reaction of this event, you can add your process by realizing this method.
	 * Notice! You should not call Wait() here to prevent blocking process. 
	 * @param pMgr its container.
	 */
	virtual void OnEvent(CMultiThreadEventManager* pMgr)=0;
	/**
	 * Wait this event until OnEvent() method have been called.
	 * Notice! You should only call this method in manager thread,
	 * or you can override this method for your demands. 
	 * @return true for succeed, false for exceptional end.
	 */
	virtual bool Wait();
	/**
	 * Is this event waitable for manager thread. Default value is true.
	 * @return true or false.
	 */
	bool IsNeedWait(){return need_wait;};
	/**
	 * Enable the Wait() function. Default value is true.
	 * @param fEnable true for enable, false for not.
	 */
	void SetNeedWait(bool fEnable=true){need_wait=fEnable;};
	friend class CMultiThreadEventManager;
protected:
	//state indicators
	volatile bool is_in_processed;
	volatile bool succeed_processed;
	volatile bool need_wait;
	volatile long n_count;//signaled count
	pthread_mutex_t* p_event_lock;
	sem_t* p_event_count;
	//used for waiting mode
	sem_t finished;//finished time count
};

/**
 * Event Manager for your manager thread (main thread).
 */
class CMultiThreadEventManager
{
public:
	CMultiThreadEventManager(void);
	~CMultiThreadEventManager(void);
	/**
	 * If you want wait all events have been processed while this class destructing.
	 * Just Set it enable. Default value is true.
	 * @param fEnable true for enable, false for not.
	 */
	void SetWaitAllAtEnd(bool fEnable=true){end_wait_all=fEnable;};
	/**
	 * Is wait all events while destructing.
	 * @return true or false.
	 */
	bool IsWaitAllAtEnd(){return end_wait_all;};
	/**
	 * Signal one event, this event will asynchronous call its OnEvent() method latter.
	 * @return true for succeed, this must be the only returns, or something with your pthreads lib while false returned.
	 */
	bool SignalEvent(CMultiThreadEvent* pEvent);
protected:
	//our working thread shell
	static void* WorkThread(void* obj);
	//real thread process
	void DoWorkThread();

	std::deque<CMultiThreadEvent*> event_queue;
	pthread_mutex_t event_lock;
	pthread_t threads[PTHREAD_THREADS_MAX];
	long n_threads;
	sem_t event_count;//Non-repeated events global count
	volatile bool is_run;
	volatile bool end_wait_all;
};
#endif
